﻿using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using SdmxMl.Common;
using SdmxMl.GenericMetadata;
using SdmxMl.Manager;
using SdmxMl.Structure;
using Telerik.WinControls;
using Telerik.WinControls.Data;
using Telerik.WinControls.UI;

namespace SmsUsers
{
    /// <summary> Creates and manages SMS users Grid content</summary>
    public class GridCreator
    {
        #region Constants

        private const string TableUser = "User";
        private const string TableGroup = "Group";
        private const string ColUserId = "UID";
        private const string ColUserName = "Name";
        private const string ColUserMail = "Mail";
        private const string ColUserPhone = "Phone";
        private const string ColGroupId = "GroupID";
        private const string ColGroupRole = "Role";
        private const string UserGroupRelation = "relGrp";


        #endregion

        #region Internal Members

        private RadGridView gridView;
        public MetadataSetType metadataSet { get; private set; }
        public CodeListType cltCodeGroup { get; private set; }
        #endregion

        #region Constructor

        public GridCreator(RadGridView radGrid)
        {
            gridView = radGrid;

            // Event for defining size columns of grid combo multicell
            gridView.CellEditorInitialized += new GridViewCellEventHandler(gridView_CellEditorInitialized);
        }

        #endregion

        #region Grid Columns construction

        public void SetView(bool enableFilter, MetadataSetType mSet, CodeListType cltGrp, string selectedGroup)
        {
            metadataSet = mSet;
            AssignCodelistGroup(cltGrp);

            DataSet ds = FillDataSet();

            gridView.BeginUpdate();

            gridView.AutoGenerateHierarchy = true;
            gridView.DataSource = ds;
            gridView.DataMember = TableUser;
            gridView.Relations[0].ChildTemplate.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;

            // Combo groups
            RefreshGroups(cltCodeGroup);

            gridView.EnableFiltering = enableFilter;

            gridView.Relations[0].ChildTemplate.Columns[ColUserId].ReadOnly = true;
            gridView.MasterTemplate.Columns[ColUserId].ReadOnly = true;

            gridView.EndUpdate();

            gridView.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
            gridView.AddNewRowPosition = SystemRowPosition.Top;

            // Set visibility
            SetGroupVisibility(selectedGroup);

        }

        private void AssignCodelistGroup(CodeListType cltGrp)
        {
            cltCodeGroup = cltGrp;
            // alpha sort
            cltCodeGroup.CodeList.Sort(delegate(ISdmxHierarchyListItem p1, ISdmxHierarchyListItem p2)
            { return p1.Id.CompareTo(p2.Id); });
        }

        #endregion

        #region Group Visibility

        public void SetGroupVisibility(string groupId)
        {
            // Set visible only rows of selected group

            bool allGroups = string.IsNullOrEmpty(groupId);

            foreach (GridViewRowInfo rowInfo in gridView.ChildRows)
            {
                if (allGroups)
                    rowInfo.IsVisible = true;
                else
                {
                    rowInfo.IsVisible = true;
                    bool visible = false;
                    foreach (GridViewRowInfo childRow in rowInfo.ChildRows)
                    {
                        if (childRow.Cells[ColGroupId].Value != null)
                        {
                            if (childRow.Cells[ColGroupId].Value.ToString() == groupId)
                            {
                                visible = true;
                                break;
                            }
                        }
                    }
                    rowInfo.IsVisible = visible;

                }
            }

        }


        #endregion

        #region Data binding

        private DataSet ConstructDataSet()
        {
            DataSet ds = new DataSet();

            DataTable tUser = new DataTable(TableUser);
            tUser.Columns.Add(new DataColumn(ColUserId, typeof(string)));
            tUser.Columns.Add(new DataColumn(ColUserName, typeof(string)));
            tUser.Columns.Add(new DataColumn(ColUserMail, typeof(string)));
            tUser.Columns.Add(new DataColumn(ColUserPhone, typeof(string)));

            DataTable tGroup = new DataTable(TableGroup);

            tGroup.Columns.Add(new DataColumn(ColUserId, typeof(string)));
            tGroup.Columns.Add(new DataColumn(ColGroupId, typeof(string)));
            tGroup.Columns.Add(new DataColumn(ColGroupRole, typeof(string)));

            tUser.PrimaryKey = new DataColumn[] { tUser.Columns[ColUserId] };

            ds.Tables.Add(tUser);
            ds.Tables.Add(tGroup);

            DataRelation dr = new DataRelation(UserGroupRelation, tUser.Columns[ColUserId], tGroup.Columns[ColUserId]);
            ds.Relations.Add(dr);
            return ds;
        }

        private DataSet FillDataSet()
        {   
            DataSet ds = ConstructDataSet();
            DataTable tUser = ds.Tables[TableUser];
            DataTable tGroup = ds.Tables[TableGroup];

            foreach (AttributeValueSetType atv in metadataSet.AttributeValueSetList)
            {
                // Fill user
                tUser.Rows.Add(new object[] {
                    atv.TargetValuesTypeList[0].Value,
                    GetReportedValue(atv.ReportedAttributeList, "UNAME"),
                    GetReportedValue(atv.ReportedAttributeList, "UEMAIL"),
                    GetReportedValue(atv.ReportedAttributeList, "UPHONE")
                });

                // Fill Group(s)
                ReportedAttributeTypeList raList = new ReportedAttributeTypeList();
                atv.ReportedAttributeList.GetReportedAttributeListForConcept("GROUP", raList);
                foreach (ReportedAttributeType ragrp in raList)
                {
                    tGroup.Rows.Add(new object[] {
                        atv.TargetValuesTypeList[0].Value,
                        GetReportedValue(ragrp.ReportedAttributeList, "UGRP_ID"),
                        GetReportedValue(ragrp.ReportedAttributeList, "UROLE")
                    });
                }
            }

            return ds;
        }

        private string GetReportedValue(ReportedAttributeTypeList rlist, string id)
        {
            string s = string.Empty;
            ReportedAttributeType ra = rlist.GetReportedAttributeOfConcept(id);
            if (ra != null)
                s = ra.Value.ToString();

            return s;
        }

        #endregion

        #region Cell editor Initialized event

        /// <summary>Format multicombo for nice presentation</summary>
        /// <param name="sender"></param><param name="e"></param>
        private void gridView_CellEditorInitialized(object sender, GridViewCellEventArgs e)
        {
            RadMultiColumnComboBoxElement multiComboElement = gridView.ActiveEditor as RadMultiColumnComboBoxElement;
            if (multiComboElement != null)
            {
                multiComboElement.DropDownStyle = RadDropDownStyle.DropDown;
                multiComboElement.EditorControl.Columns[0].Width = 80;
                MultiColumnComboGridView mgv = multiComboElement.EditorControl as MultiColumnComboGridView;
                if (mgv != null)
                {
                    multiComboElement.AutoFilter = true;
                    if (multiComboElement.EditorControl.MasterTemplate.FilterDescriptors.Count == 0)
                    {
                        multiComboElement.EditorControl.FilterDescriptors.Add(multiComboElement.DisplayMember, FilterOperator.StartsWith, String.Empty);
                    }
                }

                multiComboElement.EditorControl.Columns[1].Width = 292;

                multiComboElement.PopupOpening += new CancelEventHandler(multiComboElement_PopupOpening);
            }
        }

        /// <summary>Resize multicombo editor </summary>
        /// <param name="sender"></param> <param name="e"></param>
        void multiComboElement_PopupOpening(object sender, CancelEventArgs e)
        {
            RadMultiColumnComboBoxElement element = sender as RadMultiColumnComboBoxElement;
            element.MultiColumnPopupForm.MinimumSize = new Size(410, 250);
            element.EditorControl.GridViewElement.MinSize = new Size(410, 250);
        }
        #endregion

        #region Data serialization

        public MetadataSetType FillMetaset()
        {
            DataSet ds = gridView.DataSource as DataSet;
            //           ds.AcceptChanges();
            DataTable tUser = ds.Tables[TableUser];
            DataTable tGroup = ds.Tables[TableGroup];

            metadataSet.AttributeValueSetList.Clear();

            // Fetch MSD and report for SAKE quest
            SmManager sm = new SmManager();
            MetadataStructureDefinitionType msd = sm.GetArtefact(SdmxArtefactType.MetadataStructureDefinitions,
                metadataSet.MetadataStructureRef, true) as MetadataStructureDefinitionType;
            ReportStructureType report = msd.ReportStructureList[0];

            foreach (DataRow r in tUser.Rows)
            {
                AttributeValueSetType atv = new AttributeValueSetType(msd, report, metadataSet);
                // The target values
                atv.TargetValuesTypeList.SetComponentValue(ColUserId, r[ColUserId].ToString());
                // The reported attributes
                SetRepAttValue(atv, "UNAME", new MultiLang(r[ColUserName].ToString()));
                SetRepAttValue(atv, "UEMAIL", new MultiLang(r[ColUserMail].ToString()));
                SetRepAttValue(atv, "UPHONE", new MultiLang(r[ColUserPhone].ToString()));

                // get each group
                DataRow[] childRows = r.GetChildRows(ds.Relations[0]);
                ReportedAttributeType ra = atv.ReportedAttributeList.GetReportedAttributeOfConcept("GROUP");
                int pos = atv.ReportedAttributeList.IndexOf(ra);
                atv.ReportedAttributeList.Remove(ra);

                foreach (DataRow dr in childRows)
                {
                    ReportedAttributeType rgrp = new ReportedAttributeType();
                    rgrp.ConceptID = "GROUP";
                    ReportedAttributeType rid = new ReportedAttributeType();
                    rid.ConceptID = "UGRP_ID";
                    rid.Value = new MultiLang(dr[ColGroupId].ToString());
                    rgrp.ReportedAttributeList.Add(rid);
                    rid = new ReportedAttributeType();
                    rid.ConceptID = "UROLE";
                    rid.Value = new MultiLang(dr[ColGroupRole].ToString());
                    rgrp.ReportedAttributeList.Add(rid);
                    atv.ReportedAttributeList.Insert(pos, rgrp);
                }
                metadataSet.AttributeValueSetList.Add(atv);
            }
            return metadataSet;
        }


        private void SetRepAttValue(AttributeValueSetType at, string conceptId, MultiLang ml)
        {
            ReportedAttributeType ra = at.ReportedAttributeList.GetReportedAttributeOfConcept(conceptId);
            if (ra != null)
                ra.Value = ml == null ? new MultiLang() : ml;
        }


        #endregion

        #region User exists

        public bool ExistUser(string uid)
        {
            bool exist = false;
            DataSet ds = gridView.DataSource as DataSet;
            if (ds != null)
                exist = ds.Tables[TableUser].Rows.Find(uid) != null;

            return exist;
        }
        #endregion

        #region Add User

        public void AddUser(string uid, string name, string mail, string grpId, bool isGroupAdmin)
        {
            DataSet ds = gridView.DataSource as DataSet;
            if (ds != null)
            {
                DataRow row = ds.Tables[TableUser].NewRow();
                row[ColUserId] = uid;
                row[ColUserName] = name;
                row[ColUserMail] = mail;
                ds.Tables[TableUser].Rows.InsertAt(row, 0);

                row = ds.Tables[TableGroup].NewRow();
                row[ColUserId] = uid;
                row[ColGroupId] = grpId;
                row[ColGroupRole] = isGroupAdmin ? "Maintenance" : string.Empty;
                ds.Tables[TableGroup].Rows.InsertAt(row, 0);
            }

        }
        #endregion

        #region Refresh Group list

        public void RefreshGroups(CodeListType cltGroup)
        {
            AssignCodelistGroup(cltGroup);

            // Combo groups
            GridViewMultiComboBoxColumn col = new GridViewMultiComboBoxColumn();
            col.DataSource = cltCodeGroup.CodeList.GetTableRepresentation();
            col.DisplayMember = "Code";
            col.ValueMember = "Code";
            col.FieldName = "GroupId";
            col.HeaderText = "Group ID";

            gridView.Relations[0].ChildTemplate.Columns.Remove("GroupId");
            gridView.Relations[0].ChildTemplate.Columns.Insert(1, col);

        }
        #endregion

    }

}
